#include <iostream>
/**
 * shared_ptr 强智能指针，带有自动计数功能
 * weak_ptr 弱智能指针，没有自动计数功能
 * weak_ptr弱智能指针观察shared_ptr强智能指针
 * shared_ptr强智能指针观察资源内存
 * 
 */

using namespace std;

// 定义一个引用器
class RefCounter
{
public:
    RefCounter(unsigned int val = 0):cnt(val) {}
    ~RefCounter() {}
    void add_Ref(void)
    {
        this->cnt ++;
    }
    void delete_Ref(void)
    {
        this->cnt --;
    }
    int get_cnt(void) const
    {
        return this->cnt;
    }
private:
    unsigned int cnt;
};

template <typename T>
class MySharedPtr
{
public:
    // 默认构造函数
    MySharedPtr(T* ptr = nullptr);
    // 析构函数
    ~MySharedPtr();
    // 拷贝构造函数
    MySharedPtr(const MySharedPtr<T> &ptr);
    // 运算符重载函数
    MySharedPtr<T>& operator=(const MySharedPtr<T> &ptr);
    T& operator*(void)
    {
        return *mptr;
    }
    T* operator->(void)
    {
        return mptr;
    }
private:
    T* mptr;
    RefCounter *counter;
};

template <typename T>
// 默认构造函数
MySharedPtr<T>::MySharedPtr(T* ptr):mptr(ptr)
{
    if(mptr != nullptr)
        this->counter = new RefCounter(1);
    else 
        this->counter = new RefCounter(0);
    cout << "调用了默认构造函数" << endl;
}
template <typename T>
// 析构函数
MySharedPtr<T>::~MySharedPtr()
{
    this->counter->delete_Ref();
    cout << "当前计数是：" << this->counter->get_cnt() << endl;
    // 如果引用计数为0，则释放空间
    if(0 == this->counter->get_cnt())
    {
        delete this->mptr;
        this->mptr = nullptr;
        delete this->counter;
        this->counter = nullptr;
        cout << "调用了析构函数，内存释放" << endl;
    }
    else 
    {
        cout << "引用计数不为0，仍有指针指向" << endl;
    }
    
}

template <typename T>
// 拷贝构造函数
MySharedPtr<T>::MySharedPtr(const MySharedPtr<T> &ptr)
{   
    this->mptr = ptr.mptr;
    this->counter = ptr.counter;
    this->counter->add_Ref();
    cout << "调用了拷贝构造函数" << endl;
}

// 运算符重载=
template <typename T>
// 返回值 域::函数名(形参) {函数体}
MySharedPtr<T>& MySharedPtr<T>::operator=(const MySharedPtr<T> &ptr)
{
    if(this == &ptr)
        return *this;
    // 如果对象此时还有指向其他引用的资源时，首先先减少一个引用计数，再去判断是否引用计数为空，如果为空说明当前智能指针是最后一个，需要释放空间
    this->counter->delete_Ref();
    if(0 ==this->counter->get_cnt())
    {
        // 注意这里删除的是他曾经指向的其他资源
        delete this->mptr;
        this->mptr = nullptr;
        delete this->counter;
		this->counter = nullptr;
    }
    // 重新给智能指针赋值
    this->counter = ptr.counter;
    this->mptr = ptr.mptr;
    this->counter->add_Ref();
    cout << "调用了赋值重载函数" << endl;

    return *this;
}

int main(int argc, char const *argv[])
{
    MySharedPtr<int> ptr1(new int);
    MySharedPtr<int> ptr2(ptr1);
    MySharedPtr<int> ptr3;
    ptr3 = ptr2;
    *ptr1 = 20;

    cout << *ptr2 << ":" << *ptr3 << endl;
    return 0;
}
